﻿namespace Home.Security.Authentication.IdentityProviders
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Newtonsoft.Json.Linq;
    using Home.Security.Authentication.Repository;
    using System.Web;
    using Newtonsoft.Json;
    using Http;

    internal abstract class IdentityProvider
    {
        public abstract Task<string> GenerateLoginUriAsync();
        public virtual Task<string> GetAuthorizationCodeAsync(AuthenticationParameter state, NameValueCollection queryString)
        {
            var result = queryString["code"];
            return Task.FromResult(string.IsNullOrEmpty(result) ? null : result);
        }

        public abstract Task<string> GenerateAccessTokenRequestUriAsync(AuthorizationCodeResult authorization);
        public abstract Task<AccessTokenResult> ParseAccessTokenResponseAsync(AuthorizationCodeResult authorization, IDictionary<string, string> values);

        public abstract Task<string> GenerateRefreshTokenRequestUriAsync(AuthenticationEntity entity);
        public abstract Task<RefreshTokenResult> ParseRefreshTokenResponseAsync(AuthenticationEntity entity, IDictionary<string, string> values);

        public abstract Task<string> GenerateVerifyAccessTokenRequestUriAsync(AuthenticationEntity entity);
        public abstract Task<VerifyAccessTokenResult> ParseVerifyAccessTokenResponseAsync(AuthenticationEntity entity, IDictionary<string, string> values);

        public abstract Task<string> GetUserKeyAsync(AuthenticationEntity entity);
        public abstract Task UpdateUserSnsAsync(ApplicationUserEntity entity, SnsResult sns);

        public abstract Task<string> GenerateSnsRequestUriAsync(AuthenticationEntity entity);
        public abstract Task<SnsResult> ParseSnsResponseAsync(AuthenticationEntity entity, IDictionary<string, string> values);

        public abstract IDictionary<string, string> ParseHttpResponse(string content);

        protected static string GenerateLoginState(AuthenticationType type)
        {
            var id = Guid.NewGuid();
            var trackId = Guid.NewGuid();
            var parameter = new AuthenticationParameter(id, trackId, type)
            {
                TimeStamp = DateTimeOffset.UtcNow,
            };
            var data = SecurityHelper.ProtectData(parameter);
            return HttpUtility.UrlEncode(data);
        }

        protected static IDictionary<string, string> ParseHttpResponseJson(string json)
        {
            if (string.IsNullOrEmpty(json))
            {
                return null;
            }

            var result = new Dictionary<string, string>();
            var token = JToken.Parse(json);
            foreach (JProperty property in token)
            {
                var name = property.Name;
                var value = property.Value;
                result.Add(name, value == null ? string.Empty : value.ToString(Formatting.None));
            }

            return result;
        }

        protected static IDictionary<string, string> ParseHttpResponseQueryString(string queryString)
        {
            if (string.IsNullOrEmpty(queryString))
            {
                return null;
            }

            var queries = HttpUtility.ParseQueryString(queryString, Encoding.UTF8);
            var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (var key in queries.AllKeys)
            {
                result[key] = queries[key];
            }

            return result;
        }

        protected static IDictionary<string, string> ParseHttpResponseJavaScriptCallbackJson(string content)
        {
            if (string.IsNullOrEmpty(content))
            {
                return null;
            }

            content = content.Trim();
            if (content.StartsWith("callback", StringComparison.OrdinalIgnoreCase))
            {
                var index = content.IndexOf('(', 8);
                content = content.Substring(index + 1);
                index = content.LastIndexOf(')');
                content = content.Substring(0, index);

                return ParseHttpResponseJson(content);
            }

            return null;
        }

        protected static bool CheckHttpResponseJavaScriptCallbackJson(string content)
        {
            if (string.IsNullOrEmpty(content))
            {
                return false;
            }

            content = content.Trim();

            var result = content.StartsWith("callback", StringComparison.OrdinalIgnoreCase);
            return result;
        }

        protected static bool CheckHttpResponseJson(string content)
        {
            if (string.IsNullOrEmpty(content))
            {
                return false;
            }

            content = content.Trim();
            var result = (content.StartsWith("{", StringComparison.OrdinalIgnoreCase) && content.EndsWith("}", StringComparison.OrdinalIgnoreCase))
                || (content.StartsWith("[", StringComparison.OrdinalIgnoreCase) && content.EndsWith("]", StringComparison.OrdinalIgnoreCase));
            return result;
        }

        protected static async Task<byte[]> GetPhotoAsync(string uri)
        {
            var response = await HttpHelper.GetBinaryAsync(uri);
            if (response == null || response.Body == null || response.Body.Length == 0)
            {
                return null;
            }

            return response.Body;
        }
    }
}
